﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using PersonaLibrary.Data;
using PersonaLibrary.Search;
using PersonaLibrary.ViewModel.SearchViewModel;

namespace PersonaLibrary.ViewModel.SearchPanelViewModel
{
	internal class SearchPanelViewModel<TEntity> : UserControlViewModel
		where TEntity : class, IDBEntity
	{
		private RelayCommand _commitCommand;
        private RelayCommand _addNewRowCommand;
        private RelayCommand _removeRowCommand;

        private readonly ObservableCollection<SearchItemModel> _searchedItems = new ObservableCollection<SearchItemModel>();

		public SearchPanelViewModel()
        {
			AddNewRow();
        }

        public ObservableCollection<SearchItemModel> SearchedItems
        {
            get
            {
                return _searchedItems;
            }
        }

        public RelayCommand CommitCommand
        {
            get
            {
                if (_commitCommand == null)
                    _commitCommand = new RelayCommand(param => Commit(), param => CanCommit());
                return _commitCommand;
            }
        }

        public RelayCommand AddNewRowCommand
        {
            get
            {
                if (_addNewRowCommand == null) 
					_addNewRowCommand = new RelayCommand(param => AddNewRow(), param => true);
                return _addNewRowCommand;
            }
        }

        public RelayCommand RemoveRowCommand
        {
            get
            {
                if (_removeRowCommand == null) 
					_removeRowCommand = new RelayCommand(param => RemoveRow((SearchItemModel)param), param => param is SearchItemModel);
                return _removeRowCommand;
            }
        }

        private void AddNewRow()
        {
			if (SearchedItems.Count == 0)
				SearchedItems.Add(new SearchItemModel { Properties = CreateProperties(), BinaryEnable = false});
			else
				SearchedItems.Add(new SearchItemModel { Properties = CreateProperties(), SelectedBinaryOperator = "И"});
        }

        private void RemoveRow(SearchItemModel arg)
        {
            _searchedItems.Remove(arg);
        }

		private static List<SearchCriteria> CreateProperties()
		{
			Stopwatch timer = Stopwatch.StartNew();
			var map = new ExeConfigurationFileMap {ExeConfigFilename = @"Config\unity.config"};
			var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
			var section = (UnityConfigurationSection)config.GetSection("unity");
			var container = new UnityContainer();
			section.Containers[typeof(TEntity).Name + "Search"].Configure(container);

			List<SearchCriteria> result = container.Resolve<List<SearchCriteria>>("properties");
			Debug.WriteLine(string.Format("Search properties resolve: {0}", timer.Elapsed));
			return result;
		}

    	public event Action<string> QueryCreated;

        public virtual void Commit()
        {
			StringBuilder builder = new StringBuilder();

        	builder.AppendFormat(@"Select {0}.* from {0} ", typeof(TEntity).Name);

        	bool isInnerAdded = false;
        	foreach (SearchItemModel searchItemModel in SearchedItems)
        	{
				if (!string.IsNullOrEmpty(searchItemModel.SelectedProperty.Join) &&
					!builder.ToString().Contains(searchItemModel.SelectedProperty.Join))
				{
					if (!isInnerAdded)
					{
						builder.Append("inner");
						isInnerAdded = true;
					}

					builder.Append(" join ");
					builder.Append(searchItemModel.SelectedProperty.Join);
					builder.Append(" ");
				}
        	}

        	builder.Append("where ");
			for (int i = 0; i < SearchedItems.Count; i++ )
			{
				SearchedItems[i].SelectedProperty.Value = SearchedItems[i].Value;

				SearchedItems[i].SelectedProperty.CreateWhere(builder);

				if (SearchedItems.Last() != SearchedItems[i])
				{
					if (SearchedItems[i + 1].SelectedBinaryOperator == "И")
						builder.Append(" and ");

					if (SearchedItems[i + 1].SelectedBinaryOperator == "ИЛИ")
						builder.Append(" or ");
				}
			}

			if (QueryCreated != null)
				QueryCreated(builder.ToString());
        }

        public virtual bool CanCommit()
        {
        	foreach (SearchItemModel searchItemModel in SearchedItems)
        	{
        		if(string.IsNullOrEmpty(searchItemModel.Value))
        			return false;
        	}

            return true;
        }
	}
}
